package dao.jdbc;

import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;

import model.Adresse;
import model.Anlage;
import model.Teilnehmer;
import model.Termin;
import model.Termin.TerminArt;
import dao.jdbc.JdbcDao.JdbcDAO;

public class TerminJdbcDao implements JdbcDAO<Termin> {

	private PreparedStatement updateStatement = null;
	private PreparedStatement insertStatement = null;
	private PreparedStatement deleteStatement = null;
	private PreparedStatement findByIdStatement = null;
	private PreparedStatement findAllStatement = null;


	AdresseJdbcDao adressJdbc = new AdresseJdbcDao();
	TeilnehmerJdbcDao teilnehmerJdbc = new TeilnehmerJdbcDao();
	AnlageJdbcDao anlageJdbc = new AnlageJdbcDao();

	SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm");

	private static final String SQL_INSERT = "INSERT INTO terminplaner.termine(timestamp, thema, beschreibung, terminanfang, terminende, terminart, prioritaet)"
			+ "VALUES(? ,?, ?, ?, ?, ?, ?)";

	private static final String SQL_UPDATE = "UPDATE terminplaner.termine "
			+ "SET timestamp=?, thema=?, beschreibung=?, terminanfang=?, terminende=?,  terminart=?, prioritaet=? "
			+ "WHERE id=?";

	private static final String SQL_SELECT_BY_ID = "SELECT id, timestamp, thema, beschreibung, terminanfang, terminende, terminart, prioritaet "
			+ "FROM terminplaner.termine " + "WHERE id=?";

	private static final String SQL_SELECT_ALL = "SELECT id, timestamp, thema, beschreibung, terminanfang, terminende, terminart, prioritaet "
			+ "FROM terminplaner.termine";

	private static final String SQL_DELETE_BY_ID = "DELETE FROM terminplaner.termine "
			+ "WHERE id=?";

	@Override
	public int save(Connection con, Termin data) throws IOException {
		if (con == null)
			throw new IllegalArgumentException(
					"Connection darf nicht null sein!");
		if (data == null)
			throw new IllegalArgumentException("Daten duerfen nicht null sein!");

		int changed = 0;

		if (data.neu())
		{
			changed = insert(con, data, new Date());
			adressJdbc.save(con, data.getAdresse());

			for(Teilnehmer teilnehmer : data.getTeilnehmer())
			    teilnehmerJdbc.save(con, teilnehmer);
			
	     for(Anlage anlage : data.getAnlagen())
         anlageJdbc.save(con, anlage);
			   
		
		}
		else if (!data.neu())
		{			changed = update(con, data, new Date());
    adressJdbc.save(con, data.getAdresse());

    for(Teilnehmer teilnehmer : data.getTeilnehmer())
        teilnehmerJdbc.save(con, teilnehmer);
    
     for(Anlage anlage : data.getAnlagen())
       anlageJdbc.save(con, anlage);
		
		}
		return changed;
	}

	private int insert(Connection con, Termin data, Date timestamp)
			throws IOException {
		if (timestamp == null)
			throw new IllegalArgumentException(
					"timestamp darf nicht null sein!");

		int recordsAffected = 0;
		try {
				insertStatement = con.prepareStatement(SQL_INSERT,PreparedStatement.RETURN_GENERATED_KEYS);

			insertStatement.setTimestamp(1, JdbcDao.toSqlTimestamp(timestamp));
			insertStatement.setString(2, data.getThema());
			insertStatement.setString(3, data.getBeschreibung());
			insertStatement.setString(4, sdf.format(data.getTerminAnfang()));
			insertStatement.setString(5, sdf.format(data.getTerminEnde()));
			insertStatement.setString(6, data.getTerminArt().getKey());
			insertStatement.setInt(7, data.getPrioritaet().intValue());

			recordsAffected = insertStatement.executeUpdate();
			ResultSet rs = insertStatement.getGeneratedKeys();
			while (rs.next()) {
				data.setID(rs.getLong(1));
				data.setTimestamp((Date) timestamp.clone());
			}
		} catch (SQLException e) {
			throw new IOException("Fehler bei InsertStatement!", e);
		}
		return recordsAffected;
	}

	private int update(Connection con, Termin data, Date timestamp)
			throws IOException {
		if (timestamp == null)
			throw new IllegalArgumentException(
					"timestamp darf nicht null sein!");

		int recordsAffected = 0;
		try {
				updateStatement = con.prepareStatement(SQL_UPDATE);

			updateStatement.setTimestamp(1, JdbcDao.toSqlTimestamp(timestamp));
			updateStatement.setString(2, data.getThema());
			updateStatement.setString(3, data.getBeschreibung());
			updateStatement.setString(4, sdf.format(data.getTerminAnfang()));
			updateStatement.setString(5, sdf.format(data.getTerminEnde()));
			updateStatement.setString(6, data.getTerminArt().getKey());
			updateStatement.setInt(7, data.getPrioritaet().intValue());

			updateStatement.setLong(8, data.getId());

			recordsAffected = updateStatement.executeUpdate();
			data.setTimestamp((Date) timestamp.clone());

		} catch (SQLException e) {
			throw new IOException("Fehler bei UpdateStatement!", e);
		}
		return recordsAffected;
	}

	@Override
	public int delete(Connection con, Termin data) throws IOException {
		if (con == null)
			throw new IllegalArgumentException(
					"Connection darf nicht null sein!");
		if (data == null)
			throw new IllegalArgumentException("Daten duerfen nicht null sein!");

		int recordsAffected = 0;
		try {
				deleteStatement = con.prepareStatement(SQL_DELETE_BY_ID);
			if (data.getId() == null)
				throw new IllegalArgumentException(
						"Termin befindet sich nicht in der Datenbank!");
			deleteStatement.setLong(1, data.getId());

			recordsAffected = deleteStatement.executeUpdate();
			adressJdbc.delete(con, data.getAdresse());
			for(Teilnehmer teilnehmer : data.getTeilnehmer())
			{
			teilnehmerJdbc.delete(con, teilnehmer );
	  	}
			
			data.idLoeschen();
		} catch (SQLException e) {
			throw new IOException("Fehler bei DeleteStatement", e);
		}
		return recordsAffected;

	}

	@Override
  public Termin findById(Connection con, Long id) throws IOException {
    if (con == null)
      throw new IllegalArgumentException("Connection darf nicht null sein!");

    if (id == null) {
      throw new IllegalArgumentException("ID darf nicht null sein");
    }
    
    Termin termin = null;
    try {
        findByIdStatement = con.prepareStatement(SQL_SELECT_BY_ID);
      findByIdStatement.setLong(1, id);

      ResultSet rs = findByIdStatement.executeQuery();
      rs.next();
        
        termin = createTerminFromResultSet(con, rs);
      
      if(!rs.isLast())
         throw new IOException("Fehler in der Datenstruktur, id darf jeweils nur einmal vorkommen!");
       
      
    } catch (SQLException e) {
      throw new IOException("Fehler bei findByID Statement!", e);
    }
    if(termin == null)
      throw new IOException("Termin mit dieser ID nicht gefunden!");
    return termin;

  }


	
	@Override
	  public ArrayList<Termin> findAll(Connection con) throws IOException {
	    if (con == null)
	      throw new IllegalArgumentException("Connection darf nicht null sein!");

	    ArrayList<Termin> termine = new ArrayList<Termin>();
	    Termin termin = null;
	    
	    try {
	        findAllStatement = con.prepareStatement(SQL_SELECT_ALL);

	      ResultSet rs = findAllStatement.executeQuery();
	      while (rs.next()) {
	        
	      termin = createTerminFromResultSet(con, rs);
	      termine.add(termin);
	      }
	    } catch (SQLException e) {
	      throw new IOException("Fehler bei findByID Statement!", e);
	    }

	    return termine;

	  }

	
	private Termin createTerminFromResultSet(Connection con, ResultSet rs) throws SQLException, IOException
	{
	  
	  Termin termin = null;
	  SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm");  
    
	  Long id = new Long(rs.getInt("id"));
    String thema = rs.getString("thema");
    String beschreibung = rs.getString("beschreibung");
    Date terminAnfang;
    Date terminEnde;
    try {
      terminAnfang = sdf.parse(rs.getString("terminanfang"));
      terminEnde = sdf.parse(rs.getString("terminende"));
    } catch (ParseException e) {
      throw new IOException("Fehler bei findByID Statement! - Fehler beim parsen von Date", e);
    }
    
    Integer prioritaet = rs.getInt("prioritaet");
    TerminArt terminArt = TerminArt.getTerminArt(rs.getString("terminart"));        
    Adresse adresse = adressJdbc.findByTerminId(con, id);
    
    
    termin = new Termin(thema, beschreibung, terminAnfang, terminEnde, terminArt, prioritaet, adresse);
    
    ArrayList<Teilnehmer> teilnehmerliste =teilnehmerJdbc.findByTerminId(con, id);
    for(Teilnehmer teilnehmer : teilnehmerliste)
         termin.addTeilnehmer(teilnehmer);
    

    
    ArrayList<Anlage> anlagen= anlageJdbc.findByTerminId(con, id);
    

    
    
    for(Anlage anlage : anlagen)
          termin.addAnlage(anlage);
         
	

    
    termin.setID(id);
    termin.setTimestamp(new Date());
	  
	  return termin;
	  
	  
	}


}
